package com.hzhq.contract.controller;

import cn.hutool.core.collection.CollUtil;
import com.hzhq.contract.bean.dto.AttachmentDTO;
import com.hzhq.contract.bean.entity.Attachment;
import com.hzhq.contract.bean.vo.AttachmentVO;
import com.hzhq.contract.convert.AttachmentConvertBasic;
import com.hzhq.contract.result.Result;
import com.hzhq.contract.service.AttachmentService;
import com.hzhq.contract.status.DefaultValue;
import com.hzhq.contract.util.ConvertUtil;
import com.hzhq.contract.util.EncryptUtil;
import com.hzhq.contract.util.Page2ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.message.Message;
import org.bson.types.Binary;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.naming.directory.Attributes;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.text.DateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: hzhq1255
 * @mail: hzhq1255@163.com
 * @date: 2021/4/13 18:23
 * @desc:
 */
@Slf4j
@Api(tags = "合同附件管理")
@CrossOrigin
@RestController
@ResponseBody
@RequestMapping("/api/v1/contracts/{contractId}/attachments")
public class AttachmentController {


    @Autowired
    AttachmentService attachmentService;


    private AttachmentDTO fileConvertToAttachmentDto(String contractId,MultipartFile file) throws IOException,NoSuchAlgorithmException{
        AttachmentDTO attachment;
        String md5 = EncryptUtil.getMd5File(file.getInputStream());
        attachment = AttachmentDTO.builder()
                .contractId(contractId)
                .attachName(file.getOriginalFilename())
                .contentType(file.getContentType())
                .size(file.getSize())
                .content(new Binary(file.getBytes()))
                .md5(md5)
                .path("/contract/" + contractId + "/attachment/" + md5)
                .deleted(DefaultValue.NOT_DELETED)
                .uploadTime(new Date()).build();
        return attachment;
    }

    @ApiOperation(value = "获取所有文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId", value = "当前合同", paramType = "path", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "currentPage", value = "当前页", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer"),
            @ApiImplicitParam(name = "pageSize", value = "每页个数", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer"),
            @ApiImplicitParam(name = "attachName", value = "附件名称", paramType = "query", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "md5", value = "文件md5", paramType = "query", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "path", value = "路径", paramType = "query", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "uploadTime", value = "上传时间", paramType = "query", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "deleted", value = "删除标志", paramType = "query", dataTypeClass = Integer.class, dataType = "Integer")
    })
    @ResponseBody
    @RequestMapping(value = "/currentPage/{currentPage}/pageSize/{pageSize}", method = RequestMethod.GET)
    private Result<Object> getPageByExample(@PathVariable("contractId") String contractId,
                                            @PathVariable("currentPage") Integer currentPage,
                                            @PathVariable("pageSize") Integer pageSize,
                                            @RequestParam(value = "attachName", required = false) String attachName,
                                            @RequestParam(value = "md5", required = false) String md5,
                                            @RequestParam(value = "contentType", required = false) String contentType,
                                            @RequestParam(value = "path", required = false) String path,
                                            @RequestParam(value = "uploadTime", required = false) String uploadTime,
                                            @RequestParam(value = "deleted", defaultValue = DefaultValue.NOT_DELETED_STRING) Integer deleted) {
        AttachmentDTO attachment = new AttachmentDTO();
        attachment.setDeleted(deleted);
        attachment.setContractId(contractId);
        if (null != attachName) {
            attachment.setAttachName(attachName);
        }
        if (null != md5) {
            attachment.setMd5(md5);
        }
        if (null != contentType) {
            attachment.setContentType(contentType);
        }
        if (null != path) {
            attachment.setContentType(path);
        }
        if (null != uploadTime) {
            attachment.setUploadTime(ConvertUtil.stringToDate(uploadTime));
        }
        Page<AttachmentVO> attachmentPage = attachmentService.searchAllPageByExample(attachment, currentPage, pageSize).map(AttachmentConvertBasic.INSTANCE::dtoToVO);
        return Result.successWithData(Page2ResultUtil.getPageData(attachmentPage));
    }

    @ApiOperation(value = "获取所有文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId", value = "当前合同", paramType = "path", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "currentPage", value = "当前页", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer"),
            @ApiImplicitParam(name = "pageSize", value = "每页个数", paramType = "path", dataTypeClass = Integer.class, dataType = "Integer"),
            @ApiImplicitParam(name = "keyword", value = "关键字", paramType = "query", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "deleted", value = "删除标志", paramType = "query", dataTypeClass = Integer.class, dataType = "Integer")
    })
    @ResponseBody
    @RequestMapping(value = "/search/currentPage/{currentPage}/pageSize/{pageSize}", method = RequestMethod.GET)
    private Result<Object> searchPageByQuery(@PathVariable("contractId") String contractId,
                                             @PathVariable("currentPage") Integer currentPage,
                                             @PathVariable("pageSize") Integer pageSize,
                                             @RequestParam(value = "keyword", required = false) String keyword,
                                             @RequestParam(value = "deleted", required = false, defaultValue = DefaultValue.NOT_DELETED_STRING) Integer deleted) {
        final Query query = new Query();
        final Criteria criteria =  new Criteria();
        List<Criteria> ands = new ArrayList<>();
        List<Criteria> ors = new ArrayList<>();
        ands.add(Criteria.where(Attachment.CONTRACT_ID_FIELD).is(new ObjectId(contractId)));
        ands.add(Criteria.where(Attachment.DELETED_FIELD).is(deleted));
        if (null != keyword) {
            ors.add(Criteria.where(Attachment.ATTACH_NAME_FIELD).regex("^.*" + keyword + ".*$"));
            ors.add(Criteria.where(Attachment.MD5_FIELD).regex("^.*" + keyword + ".*$"));
            ors.add(Criteria.where(Attachment.PATH_FIELD).regex("^.*" + keyword + ".*$"));
            criteria.orOperator(ors.toArray(Criteria[]::new));
        }
        criteria.andOperator(ands.toArray(Criteria[]::new));
        query.addCriteria(criteria);
        Page<AttachmentVO> attachmentPage = attachmentService.searchAllPageByQuery(query, currentPage, pageSize).map(AttachmentConvertBasic.INSTANCE::dtoToVO);
        return Result.successWithData(Page2ResultUtil.getPageData(attachmentPage));
    }

    @ApiOperation(value = "附件上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId", value = "当前合同", paramType = "path", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "file", value = "文件", paramType = "body", dataTypeClass = List.class, dataType = "List"),
    })
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    private Result<Object> save(@PathVariable("contractId") String contractId,
                                @RequestParam("file") MultipartFile file) {
        AttachmentDTO attachment;
        try {
            attachment = this.fileConvertToAttachmentDto(contractId,file);
            AttachmentDTO currentAttachment = attachmentService.getOneByContractIdAndMd5(contractId, attachment.getMd5());
            if (currentAttachment != null) {
                attachment.setAttachId(currentAttachment.getAttachId());
                attachmentService.save(attachment);
                return Result.successWithMsgAndData("原文件存在，已覆盖上传",currentAttachment.getAttachId());
            }
            AttachmentDTO saveAttachment = attachmentService.save(attachment);
            return Result.successWithMsgAndData("文件上传成功",saveAttachment.getAttachId());
        } catch (IOException | NoSuchAlgorithmException e) {
            e.printStackTrace();
            return Result.errorWithMsg("文件上传失败");
        }
    }

    @ApiOperation(value = "附件预览")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId", value = "当前合同", paramType = "path", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "attachId", value = "附件", paramType = "path", dataTypeClass = String.class, dataType = "String"),
    })
    @RequestMapping(value = "/view/{attachId}", method = RequestMethod.GET)
    private ResponseEntity<Object> view(@PathVariable("contractId") String contractId,
                                        @PathVariable("attachId") String attachId,
                                        @RequestHeader(value = "User-Agent",required = false) String userAgent) {
        AttachmentDTO attachment = attachmentService.getOneByContractIdAndAttachId(contractId, attachId);
        try {
            if (attachment != null){
                String fileName = "";
                fileName = new String(attachment.getAttachName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
                if (null != userAgent){
                    String agent = userAgent.toUpperCase();
                    if (agent.indexOf("MSIE") > 0 || (agent.indexOf("GECKO") > 0 && agent.indexOf("RV:11") > 0)) {
                        fileName = URLEncoder.encode(attachment.getAttachName(), StandardCharsets.UTF_8.name());
                    } else {
                        fileName = new String(attachment.getAttachName().getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
                    }
                }
                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION,"attachment; fileName=" + fileName)
                        .header(HttpHeaders.CONTENT_TYPE, attachment.getContentType())
                        .header(HttpHeaders.CONTENT_LENGTH, attachment.getSize() + "")
                        .header("Connection", "close")
                        .body(attachment.getContent().getData());
            }
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("附件不存在");
        }catch (UnsupportedEncodingException e){
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("下载出错");
        }
    }


    @ApiOperation(value = "删除附件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "contractId", value = "当前合同", paramType = "path", dataTypeClass = String.class, dataType = "String"),
            @ApiImplicitParam(name = "file", value = "文件", paramType = "body", dataTypeClass = List.class, dataType = "List"),
    })
    @RequestMapping(value = "/{attachId}", method = RequestMethod.DELETE)
    private Result<Object> deleteByContractIdAndAttachId(@PathVariable("contractId") String contractId,
                                                         @PathVariable("attachId") String attachId) {
        String delId = attachmentService.deleteByContractIdAndAttachId(contractId, attachId);
        if(delId == null){
            return Result.errorWithMsg("删除失败");
        }
        return Result.successWithMsgAndData("删除成功",delId);
    }


}
